package cn.com.wxd.common.file;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Title:文件下载工具
 * Description:cn.com.wxd.util.file
 * 
 * Company: Amumu管理平台
 * Copyright: Copyright (c) 2016
 * All right reserved.
 * Created time: 2017-1-4 上午11:51:48
 *
 * @author WangXuDong
 * @version 2.0
 */
public class FileDownLoad {
	/**
	 * 文件流输出下载
	 * @param response
	 * @param attach
	 * @throws IOException
	 */
	public void fileDownload(HttpServletResponse response, File attach) throws IOException {
		OutputStream os;
        FileInputStream fis;
        ByteBuffer buff;
        long filesize = attach.length();
     // 设置Content-Length大小
	 	response.setHeader("Content-Length", String.valueOf(filesize));
		os = response.getOutputStream();
		fis = new FileInputStream(attach);
		//这里使用了nio方式进行文件的下载
		FileChannel fileChannel = fis.getChannel();
		//512KB的计算机内存缓冲区
		//使用allLocateDirect是因为直接操作系统分配缓冲，对JVM内存没有影响，而allocte是操作jvm来分配缓冲，参数都是缓冲的大小，单位字节
		buff = ByteBuffer.allocateDirect(524288);
		//131072B = 128KB
		int buffSize = 131072;
	    int nRead,nGet;
	    //128KB的缓冲数组
	    byte[] barray = new byte[buffSize];
		try {
			
		    while ((nRead = fileChannel.read(buff)) != -1){
		        if(nRead == 0){
		        	continue;
		        }
		        buff.position(0);
		        buff.limit(nRead);
		        while(buff.hasRemaining()){
		        	nGet = Math.min(buff.remaining(),buffSize);
		        	buff.get(barray,0,nGet);
		        	os.write(barray);
		        }
		        buff.clear();
		    }
		    os.flush();
		} catch (IOException e) {
			throw e;
		} finally {
			buff.clear();
			fileChannel.close();
			fis.close();
		}
	}
	/**
	 * 文件流断点续传_下载
	 * @param request
	 * @param response
	 * @param attach 要下载的文件
	 * @throws IOException,Exception 
	 */
	public void cutPointContinutFileDownload(HttpServletRequest request,HttpServletResponse response
			,File attach) throws Exception {
		OutputStream os = null;
        FileInputStream fis = null;
		BufferedInputStream buff;
		long filesize = attach.length();
		try {
			int rangeSwitch = 0;
			os = response.getOutputStream();
			fis = new FileInputStream(attach);
			long pos = 0L;
			long contentLength = 0L;
			//告诉浏览器支持断点续传
			response.setHeader("Accept-Ranges", "bytes");
			response.reset();
			String range = request.getHeader("Range");
			String rangBytes;
			if (range != null && range.trim().length() > 0 && !"null".equals(range)) {
				//设置返回代码为206即局部数据
		        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
		        try {
		            rangBytes = range.replaceAll("bytes=", "");
					if (rangBytes.endsWith("-")) { // 形如 bytes=10240-
						rangeSwitch = 1;
						pos = Long.parseLong(rangBytes.substring(0, rangBytes.indexOf("-")));
						contentLength = filesize - pos;
						
					}else { // 形如 bytes=10240-20480
						rangeSwitch = 2;
						String temp1 = rangBytes.substring(0, rangBytes.indexOf("-"));
						String temp2 = rangBytes.substring(rangBytes.indexOf("-") + 1, rangBytes.length());
						pos = Long.parseLong(temp1);
						long toLength = Long.parseLong(temp2);
						contentLength = toLength - pos + 1;
					}
		        } catch (NumberFormatException e) {
		            pos = 0;
		        }
		    }else{
		    	contentLength = filesize;
		    }
			// 设置Content-Length大小
			response.setHeader("Content-Length", String.valueOf(contentLength));
			if (rangeSwitch == 1) {
				// 拼凑响应头 Content-Range
				String contentRange = new StringBuffer()
						.append("bytes ")
						.append(String.valueOf(pos))
						.append("-")
						.append(String.valueOf(filesize - 1))
						.append("/")
						.append(String.valueOf(filesize))
						.toString();
				response.setHeader("Content-Range", contentRange);
			}else if (rangeSwitch == 2) {
				// 拼凑响应头 Content-Range，将请求头中的range改造一下，放在响应头中
				String contentRange = range.replace("=", " ") + "/" + String.valueOf(filesize);
				response.setHeader("Content-Range", contentRange);
			}
		    fis.skip(pos);
		    buff = new BufferedInputStream(fis);
		    byte[] buffer = new byte[1024];
		    int length;
		    while ((length = buff.read(buffer)) != -1) {
		    	os.write(buffer, 0, length);
		    }
		} catch (IOException e) {
			throw e;
		}finally{
		    if (os != null){
					os.close();
		    }
		    if (fis != null){
					fis.close();
		    }
		}
	}
}
